﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlTypes;

namespace dasBlog.Storage.SqlServer
{
    public class EventDataStorageProvider : SqlStorageProviderBase<dasBlog.Storage.EventEntry, EventData, dasBlogStorageSqlDataContext>
    {
        public override IEnumerable<EventEntry> Select(Moniker contextId, MonikerMatch contextMatch, QueryDescription query)
        {
            if (query == null)
            {
                if (contextMatch == MonikerMatch.Exact)
                {
                    return from EventData e in ReadContext.EventDatas
                           where e.ContextKey == contextId.ItemPath
                           orderby e.EventTime descending
                           select FromSqlType(e);
                }
                else
                {
                    return from EventData e in ReadContext.EventDatas
                           where contextId.ToString() == e.ContextKey.Substring(0, contextId.ToString().Length)
                           orderby e.EventTime descending
                           select FromSqlType(e);
                }
            }
            else
            {
                var args = new Dictionary<string, string>();
                foreach (QueryArgument arg in query.Arguments)
                {
                    args.Add(arg.Name, arg.Value);
                }

                if (query.QueryName == DateRangeQueryDescription.Name)
                {
                    DateTime @from =
                        args[DateRangeQueryDescription.FromArgument] != null ?
                        DateTime.Parse(args[DateRangeQueryDescription.FromArgument]).ToSqlRange() :
                        DateTimeTools.SqlMin;
                    DateTime @to =
                        args[DateRangeQueryDescription.ToArgument] != null ?
                        DateTime.Parse(args[DateRangeQueryDescription.ToArgument]).ToSqlRange() :
                        DateTimeTools.SqlMax;

                    if (contextMatch == MonikerMatch.Exact)
                    {
                        return from EventData e in ReadContext.EventDatas
                               where
                                  e.ContextKey == contextId.ItemPath &&
                                  e.EventTime < @to &&
                                  e.EventTime > @from
                               orderby e.EventTime descending
                               select FromSqlType(e);
                    }
                    else
                    {
                        return from EventData e in ReadContext.EventDatas
                               where contextId.ToString() == e.ContextKey.Substring(0, contextId.ToString().Length) &&
                                  e.EventTime < @to &&
                                  e.EventTime > @from
                               orderby e.EventTime descending
                               select FromSqlType(e);
                    }
                }
                else
                {
                    return null;
                }
            }
        }

        public override IEnumerable<PropertyAggregate> Aggregate(Moniker contextId, MonikerMatch contextMatch, string propertyName)
        {
            throw new NotImplementedException();
        }

        protected override void UpdateSqlTypeFromStgType(EventEntry item, EventData existingEntry)
        {
            existingEntry.Message = item.Message;
            existingEntry.EventTime = item.Time;
            existingEntry.EventCode = item.Code;
        }

        protected override EventData FromStgType(Moniker contextUri, EventEntry item)
        {
            if (item.Id != null)
            {
                Moniker id = MonikerFromStgType(item);
                return new EventData
                {
                    ContextKey = id.ItemPath,
                    Id = id.ItemId,
                    Message = item.Message.Truncate(400),
                    EventTime = item.Time.ToSqlRange(),
                    EventCode = item.Code
                };
            }
            else
            {
                return new EventData
                {
                    ContextKey = contextUri.ItemPath,
                    Id = Guid.NewGuid().ToString(),
                    Message = item.Message.Truncate(400),
                    EventTime = item.Time.ToSqlRange(),
                    EventCode = item.Code
                };
            }
        }

        protected override EventEntry FromSqlType(EventData item)
        {
            return new dasBlog.Storage.EventEntry
            {
                Code = item.EventCode,
                Message = item.Message,
                Time = item.EventTime.ToSqlRangeOrMin(),
                Id = MonikerFromSqlType(item)
            };
        }

        protected override Moniker MonikerFromSqlType(EventData newEntry)
        {
            return new Moniker(new Moniker(newEntry.ContextKey), newEntry.Id.ToString());
        }

        protected override Moniker MonikerFromStgType(EventEntry item)
        {
            return item.Id;
        }

        protected override Func<EventData, bool> MatchSingle(Moniker contextUri)
        {
            return (e) => e.ContextKey == contextUri.ItemPath &&
                          e.Id == contextUri.ItemId;
        }
    }
}
